﻿using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RAP.Framework.Libary.Configuration;
using RAP.Framework.Libary.DataSource;
using RAP.Framework.Libary.DataSource.Model.DataSource;
using RAP.Framework.Libary.DomTemplateBuilder;
using RAP.Framework.Libary.ServerCacheManager;
using RAP.Framework.Libary.SqlDataService.Service;
using RAP.Framework.Libary.Utils;
using RAP.Web.Libary.Common;
using RAP.Web.Libary.Common.Model;
using RAP.Web.Libary.Common.Model.Log;
using RAP.Web.Libary.Common.Model.Session;
using RAP.Web.Libary.Config;
using RAP.Web.Libary.Controller.Filters;
using RAP.Web.Libary.Service;
using RAP.Web.Libary.Service.DataService;
using ConfigurationManager = RAP.Framework.Libary.Configuration.ConfigurationManager;

namespace RAP.Web.Libary.AppStatup
{
  /// <summary>
  /// 服务启动基类，继承自StartupBase
  /// </summary>
  public class StartupAppBase : IStartupApp
  {
    #region 属性
    /// <summary>
    /// 服务的本地跟路径
    /// </summary>
    public string ServerRootPath { get; set; } = "/Server/";

    /// <summary>
    /// 配置文件的根路径
    /// </summary>
    public string ConfigPath { get; set; } = "~/Server/Configs/";

    /// <summary>
    /// 
    /// </summary>
    public IConfiguration Configuration { get; protected set; }

    /// <summary>
    /// 
    /// </summary>
    public Type SiteSettingType { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public Type CacheManagerType { get; set; } = typeof(CacheManager);

    /// <summary>
    /// /
    /// </summary>
    public Type SqlDataServiceType { get; set; } = typeof(SqlDataService);

    /// <summary>
    /// 
    /// </summary>
    public Type LogParamsType { get; set; } = typeof(LogParams);
    #endregion

    /// <summary>
    /// 
    /// </summary>
    /// <param name="configuration"></param>
    public StartupAppBase(IConfiguration configuration)
    {
      Configuration = configuration;
    }

    /// <summary>
    /// 配置依赖注入的服务
    /// </summary>
    /// <param name="services"></param>
    public virtual void ConfigureServices(IServiceCollection services)
    {
      services.AddCors();
      ConfigureFilters(services);

      services.AddSingleton(ConfigurationManager.AppSettings);

      services.AddSingleton(typeof(ICacheManager), CacheManagerType);

      services.AddTransient(typeof(ISqlDataService), SqlDataServiceType);

      services.AddSingleton(s => {
        return SiteSettingsBase.DataSourceConfig;
      });

      services.AddScoped(typeof(ILogParams), LogParamsType);

      ConfigureUserSession(services);

      services.InitServices<IAPIService>();

      services.AddMvc().AddRazorOptions(opts =>
      {
        ConfiguerRazorViewOptions(opts);
      }).AddRazorPagesOptions(opts =>
      {
        ConfiguerRazorPagesOptions(opts);
      });
    }

    /// <summary>
    /// 配置Razo引擎的参数
    /// </summary>
    /// <param name="opts"></param>
    protected virtual void ConfiguerRazorViewOptions(RazorViewEngineOptions opts)
    {
      var viewSuffix = RazorViewEngine.ViewExtension;
      var formats = opts.ViewLocationFormats;

      formats.Clear();
      formats.Add($"{ServerRootPath}Views/{{1}}/{{0}}{viewSuffix}");
      formats.Add($"{ServerRootPath}Views/Shared/{{0}}{viewSuffix}");
      //formats.Add( $"{ServerRootPath}Pages/{{0}}{viewSuffix}" );
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="opts"></param>
    protected virtual void ConfiguerRazorPagesOptions(RazorPagesOptions opts)
    {
      opts.RootDirectory = $"{ServerRootPath}Pages";
    }

    /// <summary>
    /// 配置Http Filter
    /// </summary>
    /// <param name="services"></param>
    public virtual void ConfigureFilters(IServiceCollection services)
    {
      //注册自定义的Filter
      services.AddMvc(config =>
      {
        ((dynamic)config).EnableEndpointRouting = false;
        config.Filters.Add(new QueryParamsFilter());
        config.Filters.Add(new NeedSessionFilter());
        config.Filters.Add(new HasMenuPowerFilter());
        config.Filters.Add(new HasDataPowerFilter());
        config.Filters.Add(new JSONResultFilter());
      });
    }

    /// <summary>
    /// 配置流水日志
    /// </summary>
    /// <param name="app"></param>
    /// <param name="services"></param>
    /// <param name="loggerFactory"></param>
    /// <returns></returns>
    public virtual ILogger ConfigureLogger(IApplicationBuilder app, IServiceProvider services, ILoggerFactory loggerFactory)
    {
      var logger = loggerFactory.CreateLogger("Startup");

      return logger;
    }

    /// <summary>
    /// 配置HttpHeader
    /// </summary>
    /// <param name="app"></param>
    /// <param name="services"></param>
    public virtual void ConfigureHttpHeaders(IApplicationBuilder app, IServiceProvider services)
    {
      app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());

      app.UseForwardedHeaders(new ForwardedHeadersOptions
      {
        ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
      });
    }

    /// <summary>
    /// 配置开发环境的参数
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <param name="logger"></param>
    protected virtual void ConfigureDevelopment(
      IApplicationBuilder app,
      IAppEnvironment env,
      IServiceProvider services,
      IConfigurationManager configuration,
      ILogger logger)
    {

      app.UseDeveloperExceptionPage();

      //初始化开发环境配置管理
      app.UseConfiguration($"{ConfigPath}SiteConfig/Config.dev.json");
    }

    /// <summary>
    /// 配置生产环境的参数
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <param name="logger"></param>
    protected virtual void ConfigureProduction(
      IApplicationBuilder app,
      IAppEnvironment env,
      IServiceProvider services,
      IConfigurationManager configuration,
      ILogger logger)
    {
      //生产环境不能返回错误详细信息
      app.UseExceptionHandler((iapp) =>
      {
        iapp.Run(async (context) =>
        {
          var ex = context.Features.Get<IExceptionHandlerFeature>()?.Error;
          //记录错误日志
          //todo...
          logger.LogError(ex.Message);
          //返回500错误
          await context.Response.WriteAsync(ServiceResult.CreateErrorResult("内部服务错误！", 500).ToString());
        });
      });

      //初始化生产环境配置管理
      app.UseConfiguration($"{ConfigPath}SiteConfig/Config.pro.json");
    }

    /// <summary>
    /// 自定义配置
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <param name="logger"></param>
    protected virtual void CustomerConfigure(
      IApplicationBuilder app,
      IAppEnvironment env,
      IServiceProvider services,
      IConfigurationManager configuration,
      ILogger logger)
    {
      if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
      {
        //设置应用程序根路径
        RAP.Framework.Libary.Utils.Extensions.APP_ROOT_PATH = env.ContentRootPath;
      }
      DataSourceHelper.AllowDebug = true;

      ConfigureSiteSettings(app, env, services, configuration);

      if (env.IsDevelopment)
      {
        //配置开发环境参数
        ConfigureDevelopment(app, env, services, configuration, logger);
      }
      else
      {
        //配置生产环境参数
        ConfigureProduction(app, env, services, configuration, logger);
      }
      LoadSiteSettings(configuration);

      if (!DebugApp(configuration))
      {
        throw new Exception("程序被终止！");
      }

      //初始化模板配置
      app.UseDomTemplate($"{ConfigPath}TSql/Configures.config");

      //文档模板调试事件，可在该事件中中断后跟踪模板执行
      DomTemplateManager.OnErrorEvent += new Action<IDictionary>((err) =>
      {
        Console.WriteLine($"数据查询错误：{err.ToJSON()}");
      });

      DataSourceHelper.OnError += new Action<IDictionary>((err) =>
      {
        //数据查询服务出错时，在此处中断查看错误信息
        Console.WriteLine($"数据查询错误：{err.ToJSON()}");
      });

      ConfigureMVC(app, env, services);

      //初始化数据查询服务
      SqlDataService.Initialize(app, logger);
    }

    /// <summary>
    /// 配置站点参数服务
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    protected virtual void ConfigureSiteSettings(
      IApplicationBuilder app,
      IAppEnvironment env,
      IServiceProvider services,
      IConfigurationManager configuration)
    {
      //初始化基础配置，不区分环境
      app.UseConfiguration($"{ConfigPath}SiteConfig/Config.json");
    }

    /// <summary>
    /// 读取站点配置
    /// </summary>
    /// <param name="configuration"></param>
    protected virtual void LoadSiteSettings(IConfigurationManager configuration)
    {
      //初始化站点参数对象
      SiteSettingsBase.LoadSettings(configuration, SiteSettingType);
    }

    /// <summary>
    /// 配置用户回话对象服务
    /// </summary>
    /// <param name="services"></param>
    protected virtual void ConfigureUserSession(IServiceCollection services)
    {
      services.AddTransient(typeof(IUserSession), typeof(UserSessionBase));
    }

    /// <summary>
    /// 配置MVC
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="services"></param>
    protected virtual void ConfigureMVC(
      IApplicationBuilder app,
      IAppEnvironment env,
      IServiceProvider services)
    {
      app.UseMvc(routes =>
      {
        routes.MapRoute("default", "{controller}/{action}", new { action = "Index", controller = "Home" });
      });
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <param name="loggerFactory"></param>
    protected virtual void Configure(
      IApplicationBuilder app,
      IAppEnvironment env,
      IServiceProvider services,
      IConfigurationManager configuration,
      ILoggerFactory loggerFactory)
    {
      var logger = ConfigureLogger(app, services, loggerFactory);

      ConfigureHttpHeaders(app, services);

      CustomerConfigure(app, env, services, configuration, logger);
    }

    /// <summary>
    /// 调试WebAPP
    /// </summary>
    /// <param name="configuration"></param>
    /// <returns></returns>
    public virtual bool DebugApp(IConfigurationManager configuration)
    {
      Console.WriteLine($"\r\n当前进程Id：{Process.GetCurrentProcess().Id}。");
      if (configuration.ToBoolean("IsDebug"))
      {
        if (!Console.IsInputRedirected)
        {
          Console.WriteLine("是否继续？(Y/N)");
          var needContinue = Console.ReadKey();
          Console.WriteLine();
          if (needContinue.Key == ConsoleKey.N)
          {
            return false;
          }

          Console.WriteLine("是否准备调试？(Y/N)");
          var needDebug = Console.ReadKey();
          Console.WriteLine();
          if (needDebug.Key == ConsoleKey.Y)
          {
            var counter = 30;
            Console.Write($"等待调试，倒计时");
            var cursorPos = new { x = Console.CursorLeft, y = Console.CursorTop };
            while (counter > 0)
            {
              Console.SetCursorPosition(cursorPos.x, cursorPos.y);
              Console.Write($"{counter}s...");
              Thread.Sleep(999);
              counter--;
            }
            Console.SetCursorPosition(cursorPos.x, cursorPos.y);
            Console.WriteLine("");
          }
        }
      }
      return true;
    }
  }
}
